import serial
import time
import os
import sys
import random
import re
import subprocess
import threading



# 定义常量
DEBUG_PORT = "COM4"
AT_PORT = "COM51"
BAUDRATE = 115200
# 定义变量
at_serial = None
debug_serial = None
#记录运行次数
runTimes		= 0
#log文件
DEBUG_LOG = ""
ADB_LOG = ""
AT_LOG = ""

# 创建日志文件
def createLogFile():
    global DEBUG_LOG, ADB_LOG, AT_LOG
    timestamp = time.strftime("%Y-%m-%d_%H_%M_%S", time.localtime())
    DEBUG_LOG = f"DEBUG_LOG_{timestamp}.log"
    ADB_LOG = f"ADB_LOG_{timestamp}.log"
    AT_LOG = f"AT_LOG_{timestamp}.log"
    
    with open(DEBUG_LOG, 'w', encoding='utf-8') as file:
        file.write("DEBUG 日志开始记录...\n")
    
    with open(ADB_LOG, 'w', encoding='utf-8') as file:
        file.write("ADB 日志开始记录...\n")
        
    with open(AT_LOG, 'w', encoding='utf-8') as file:
        file.write("AT 日志开始记录...\n")
        
# 写日志
def write_log(log, logFile):
    with open(logFile, 'a', encoding='utf-8') as file_object:
        file_object.write(str(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())) + "\r\n" + log + "\r\n")
        now_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
        print("[" + now_time+ "]" + " " + log)

#Send at instruction
def at_write(command, timeout, at_port_opened, at_result,RDY=0,CPIN=0):
	at_command = command.encode("UTF-8")
	at_port_opened.write(at_command)
 
#读取at口返回
def at_read(serial_port, logFile=""):
 rec_str = ''
 while (True):
  time.sleep(1)
  lenth = serial_port.inWaiting()
  if lenth > 0:
   rec_str = serial_port.read(size=lenth)
   try:
    rec_str = re.sub('\\x1b.*?m', "", rec_str.decode("UTF-8"), 0, re.I)
    if logFile != "":
     with open(logFile, 'a') as file_object:
      rec_str = str(time.time()) + ":" + str(
       time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())) + "\r\n" + rec_str
      file_object.write(
       str(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())) + "\r\n" + rec_str + "\r\n")
    return rec_str
   except:
    return ""
  else:
   break
 return rec_str

# 登录设备
def loginDevice():
 global DEBUG_LOG
 #确认登录失败的条件，或者，不可能失败
 while True:
#   print("等待登录... ... ")
  write_log("等待登录... ... ", DEBUG_LOG)
  time.sleep(3)
  at_write("\r\n",3,debug_serial,"OK")
  result = at_read(debug_serial)

  with open(DEBUG_LOG, 'a') as file_object:
   file_object.write(result)

  if "login:" in result:
   at_write("root\r\n",3,debug_serial,"OK")
#    print("账号输入成功")
   write_log("账号输入成功", DEBUG_LOG)
   time.sleep(2)
   at_write("oelinux123\r\n",3,debug_serial,"OK")
#    print("密码输入成功")
   write_log("密码输入成功", DEBUG_LOG)
  elif "~ #" in result:
#    print("登录成功")
   write_log("登录成功", DEBUG_LOG)
   break
  else:
   continue 

#检查debug口通信状态
def check_port_status():
 global debug_serial
 if debug_serial == None:
  try:
   debug_serial = serial.Serial(DEBUG_PORT,BAUDRATE)
  except:
   print("端口连接失败，请检查端口")
   sys.exit()

# 写入运行次数到日志
def writeRuntimesToLog():
 global runTimes
 with open(DEBUG_LOG, 'a+') as file_object:
  file_object.write("\r\n{} runtimes: {} {}\r\n".format("<"*20,runTimes,">"*20))
#  print("\r\n{} runtimes: {} {}\r\n".format("<"*20,runTimes,">"*20))
 with open(AT_LOG, 'a+') as file_object:
  file_object.write("\r\n{} runtimes: {} {}\r\n".format("<"*20,runTimes,">"*20))
#  print("\r\n{} runtimes: {} {}\r\n".format("<"*20,runTimes,">"*20))
 with open(ADB_LOG, 'a+') as file_object:
  file_object.write("\r\n{} runtimes: {} {}\r\n".format("<"*20,runTimes,">"*20))
 print("\r\n{} runtimes: {} {}\r\n".format("<"*20,runTimes,">"*20))
 runTimes += 1
 
#发送AT指令
def send_at_command(command):
        # 打开串口
        ser = serial.Serial(AT_PORT, BAUDRATE)
        ser.write((command + "\r\n").encode())
        ser.write(("\r\n").encode())
        time.sleep(1)
        response = ser.read_all().decode()
        ser.close()
        # write_log(f"at指令{command}执行结果:{response}",AT_LOG)
        with open(AT_LOG, 'a', encoding='utf-8') as file_object:
            file_object.write(str(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())) + "\r\n" + response + "\r\n")
        return response
        
#发送adb命令          
def send_adb_command(command):
    try:
        # 使用 subprocess 模块执行 adb shell 命令
        result = subprocess.run(['adb', 'shell', command], capture_output=True, text=True)
        with open(ADB_LOG, 'a', encoding='utf-8') as file_object:
            file_object.write(str(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())) + "\r\n" + result.stdout + "\r\n")
        # 返回命令的输出结果
        return result.stdout
    except Exception as e:
        return str(e)


#查看APN
def check_APN():
    write_log("开始查看APN", AT_LOG)
    result = send_at_command('AT+CGDCONT?;+CGACT?')
    return result
    
#删除APN
def remove_APN(apn_id):
    write_log(f"开始删除APN{apn_id}", AT_LOG)
    send_at_command('AT+CGDCONT={}'.format(apn_id))
    

# 写入运行次数到日志
def writeRuntimesToLog():
    global runTimes
    with open(DEBUG_LOG, 'a+') as file_object:
        file_object.write("\r\n{} runtimes: {} {}\r\n".format("<"*20, runTimes, ">"*20))
    print("\r\n{} runtimes: {} {}\r\n".format("<"*20, runTimes, ">"*20))
    runTimes += 1

# 进入测试接口
def intoTestInterface_testsdk(debug_serial, logFile):
    at_write("cd /data\r\n./test_sdk_api\r\n", 3, debug_serial, "OK")
    write_log("进入测试接口", logFile)
    time.sleep(1)
    at_write("0\n", 3 , debug_serial, "OK")
    at_read(debug_serial, DEBUG_LOG)
    time.sleep(1)
    at_write("0\n",3 , debug_serial, "OK")
    at_read(debug_serial, DEBUG_LOG)
    time.sleep(1)
    result = at_read(debug_serial, logFile)

# 退出测试接口
def exit_testsdk(debug_serial, logFile):
    at_write("-1\n-1\n", 3, debug_serial, "OK")
    result = at_read(debug_serial, logFile)

# 返回测试接口
def back_testsdk(debug_serial, logFile):
    at_write("-1\n", 3, debug_serial, "OK")
    result = at_read(debug_serial, logFile)
#创建测试APN
def set_apn_testsdk(testapn,testapn_name):
    write_log(f"开始创建测试APN{testapn}，名称{testapn_name}", DEBUG_LOG)
    # time.sleep(3)
    # at_write("0\n", 3 , debug_serial, "OK")
    # at_read(debug_serial, DEBUG_LOG)
    # time.sleep(3)
    # at_write("0\n",3 , debug_serial, "OK")
    # at_read(debug_serial, DEBUG_LOG)
    time.sleep(1)
    at_write("10\n",3 , debug_serial, "OK")
    at_read(debug_serial, DEBUG_LOG)
    time.sleep(1)
    at_write("{}\n".format(testapn),3 , debug_serial, "OK")
    time.sleep(1)
    at_read(debug_serial, DEBUG_LOG)
    at_write("3\n",3 , debug_serial, "OK")
    time.sleep(1)
    at_read(debug_serial, DEBUG_LOG)
    at_write("3\n",3 , debug_serial, "OK")
    time.sleep(1)
    at_read(debug_serial, DEBUG_LOG)
    at_write("{}\n".format(testapn_name),3 , debug_serial, "OK")
    time.sleep(1)
    at_read(debug_serial, DEBUG_LOG)
    at_write("\n",3 , debug_serial, "OK")
    time.sleep(1)
    at_read(debug_serial, DEBUG_LOG)
    at_write("\n",3 , debug_serial, "OK")
    time.sleep(1)
    result=at_read(debug_serial, DEBUG_LOG)
    if "Successful" in result:
        write_log(f"测试APN{testapn}创建成功", DEBUG_LOG)
    else:
        write_log(f"测试APN{testapn}创建失败", DEBUG_LOG)
    at_write("\n",3 , debug_serial, "OK")
    time.sleep(1)
    at_read(debug_serial, DEBUG_LOG)

#设置并启动datacall
def set_datacall1_testsdk(datacall_id,datacall_name,testapn):
    write_log(f"开始设置datacall{datacall_id}，名称{datacall_name}设置的APN为{testapn}路", DEBUG_LOG)
    time.sleep(1)
    at_write("1\n", 3 , debug_serial, "OK")
    at_read(debug_serial, DEBUG_LOG)
    time.sleep(1)
    at_write("{}\n".format(datacall_id),3 , debug_serial, "OK")
    at_read(debug_serial, DEBUG_LOG)
    time.sleep(1)
    at_write("{}\n".format(datacall_name),3 , debug_serial, "OK")
    at_read(debug_serial, DEBUG_LOG)
    time.sleep(1)
    at_write("1\n",3 , debug_serial, "OK")
    time.sleep(1)
    result1 = at_read(debug_serial, DEBUG_LOG)
    if "Successful" in result1:
        write_log(f"datacall{datacall_id}创建成功", DEBUG_LOG)
    else:
        write_log(f"datacall{datacall_id}创建失败", DEBUG_LOG)
    
    at_write("\n",3 , debug_serial, "OK")
    time.sleep(1)
    at_read(debug_serial, DEBUG_LOG)
    at_write("2\n",3 , debug_serial, "OK")
    time.sleep(1)
    at_write("{}\n".format(datacall_id), 3 , debug_serial, "OK")
    at_read(debug_serial, DEBUG_LOG)
    time.sleep(1)
    at_write("{}\n".format(testapn),3 , debug_serial, "OK")
    at_read(debug_serial, DEBUG_LOG)
    time.sleep(1)
    at_write("1\n",3 , debug_serial, "OK")
    at_read(debug_serial, DEBUG_LOG)
    time.sleep(3)
    at_write("0\n",3 , debug_serial, "OK")
    time.sleep(1)
    at_read(debug_serial, DEBUG_LOG)
    at_write("\n",3 , debug_serial, "OK")
    time.sleep(1)
    at_read(debug_serial, DEBUG_LOG)
    at_write("y\n",3 , debug_serial, "OK")
    time.sleep(1)
    result2 =at_read(debug_serial, DEBUG_LOG)
    if "Successful" in result2:
        write_log(f"datacall{datacall_id}设置APN{testapn}成功", DEBUG_LOG)
    else:
        write_log(f"datacall{datacall_id}设置APN{testapn}失败", DEBUG_LOG)
    at_write("\n",3 , debug_serial, "OK")
    time.sleep(1)
    at_read(debug_serial, DEBUG_LOG)
#启动datacall
def start_datacall_testsdk(datacall_id):
    write_log(f"开始拨号datacall：{datacall_id}", DEBUG_LOG)
    at_write("4\n",3 , debug_serial, "OK")
    time.sleep(1)
    at_read(debug_serial, DEBUG_LOG)
    at_write("{}\n".format(datacall_id),3 , debug_serial, "OK")
    time.sleep(1)
    result = at_read(debug_serial, DEBUG_LOG)
    if "Successful" in result:
        write_log(f"datacall{datacall_id}拨号成功", DEBUG_LOG)
    else:
        write_log(f"datacall{datacall_id}拨号失败", DEBUG_LOG)
    at_write("8\n",3 , debug_serial, "OK")
    time.sleep(1)
    at_read(debug_serial, DEBUG_LOG)
    at_write("{}\n".format(datacall_id),3 , debug_serial, "OK")
    time.sleep(2)
    at_read(debug_serial, DEBUG_LOG)
    at_write("\n",3 , debug_serial, "OK")
    time.sleep(1)
    at_read(debug_serial, DEBUG_LOG)

#删除datacall
def remove_datacall_testsdk(datacall_id):
    time.sleep(1)
    write_log(f"开始停止并删除datacall：{datacall_id}", DEBUG_LOG)
    at_write("5\n",3 , debug_serial, "OK")
    time.sleep(1)
    at_read(debug_serial, DEBUG_LOG)
    at_write("{}\n".format(datacall_id),3 , debug_serial, "OK")
    time.sleep(1)
    at_read(debug_serial, DEBUG_LOG)
    at_write("6\n",3 , debug_serial, "OK")
    time.sleep(1)
    at_read(debug_serial, DEBUG_LOG)
    at_write("{}\n".format(datacall_id),3 , debug_serial, "OK")
    time.sleep(1)
    result = at_read(debug_serial, DEBUG_LOG)
    if "Successful" in result:
        write_log(f"datacall{datacall_id}删除成功", DEBUG_LOG)
    else:
        write_log(f"datacall{datacall_id}删除失败", DEBUG_LOG)
    at_write("\n",3 , debug_serial, "OK")
    time.sleep(1)
    
#通过ADB命令ping测试
def ping_testsdk():
    write_log("通过ADB调试开始ping网测试", ADB_LOG)
    result = send_adb_command("ping -I rmnet_data0 -c 10 8.8.8.8")
    # write_log(f"ping测试结果:\n{result}", ADB_LOG)
    if " 100%" in result:
        write_log("data0,丢包率为100%", ADB_LOG)
    else:
        write_log("data0,丢包率不为100%,测试通过", ADB_LOG)
    result = send_adb_command("ping -I rmnet_data1 -c 10 8.8.8.8")
    # write_log(f"ping测试结果:\n{result}", ADB_LOG)
    if " 100%" in result:
        write_log("data1,丢包率为100%", ADB_LOG)
    else:
        write_log("data1,丢包率不为100%,测试通过", ADB_LOG)
        
        
#开始查看网卡信息
def check_network_info():
    write_log("开始查看网卡信息", AT_LOG)
    result = send_adb_command("ifconfig")
    return result

   
def extract_apn_ids(at_response):
    apn_ids = []
    # 按行拆分 AT 响应
    lines = at_response.splitlines()
    
    for line in lines:
        # 检查行是否以 "+CGDCONT" 开头
        if line.startswith("+CGDCONT"):
            # 按逗号分割并提取第一个字段（包含 ID）
            parts = line.split(',')
            if len(parts) > 0:
                # 提取出 "+CGDCONT: ID" 中的 ID 部分
                apn_id = parts[0].split(':')[1].strip()
                apn_ids.append(apn_id)
    
    write_log(f"APN ID 列表：{apn_ids}",AT_LOG)
    return apn_ids

def check_apn_in_list(apn_ids, target_ids):
    # 遍历每个目标ID，检查是否在apn_ids列表中
    for target_id in target_ids:
        if target_id in apn_ids:
            # print(f"APN ID {target_id} 存在于结果中")
            write_log(f"APN ID {target_id} 存在于结果中",AT_LOG)
        else:
            # print(f"APN ID {target_id} 不存在于结果中")
            write_log(f"APN ID {target_id} 不存在于结果中",AT_LOG)
#匹配网卡信息          
def extract_network_info(network_info, target_network_cards):
    # 定义正则表达式模式，匹配网卡信息
    pattern = (
        r"(\w+)\s+Link encap:\w+\s+HWaddr\s+([\w:.-]+)\s*"
        r"(?:inet addr:(\d+\.\d+\.\d+\.\d+))?\s*"
        r"(?:Bcast:(\d+\.\d+\.\d+\.\d+))?\s*"
        r"(?:Mask:(\d+\.\d+\.\d+\.\d+))?"
    )

    # 使用正则表达式查找匹配项
    matches = re.findall(pattern, network_info)
    network_cards = []
    
    # 提取匹配到的网卡信息并打印
    for match in matches:
        interface, mac_addr, inet_addr, bcast, mask = match
        network_cards.append(interface)
        # print(f"网卡: {interface}")
        write_log(f"网卡: {interface}",ADB_LOG)
        # print(f"MAC地址: {mac_addr}")
        write_log(f"MAC地址: {mac_addr}",ADB_LOG)
        # print(f"IP地址: {inet_addr if inet_addr else 'N/A'}")
        write_log(f"IP地址: {inet_addr if inet_addr else 'N/A'}",ADB_LOG)
        # print(f"广播地址: {bcast if bcast else 'N/A'}")
        write_log(f"广播地址: {bcast if bcast else 'N/A'}",ADB_LOG)
        # print(f"子网掩码: {mask if mask else 'N/A'}")
        write_log(f"子网掩码: {mask if mask else 'N/A'}",ADB_LOG)
        print("-" * 30)

    # 检查是否存在多张指定的网卡
    found_cards = [card for card in target_network_cards if card in network_cards]
    if len(found_cards) > 1:
        # print(f"存在目标网卡: {', '.join(found_cards)}")
        write_log(f"存在目标网卡: {', '.join(found_cards)}",ADB_LOG)
    else:
        # print("未找到多张目标网卡或只有一张匹配的网卡。")
        write_log("未找到多张目标网卡或只有一张匹配的网卡。",ADB_LOG)
    
#测试主函数
def main():
     # 创建的测试 APN ID 和 APN 名称
    testapn1 = '9'
    testapn1_name = 'test1'
    testapn2 = '11'
    testapn2_name = 'test2'
    #创建的datacall ID和名称
    datacall1_id = '1'
    datacall1_name = 'call1'
    datacall2_id = '2'
    datacall2_name = 'call2'
    # 需要检查的目标 APN ID
    target_ids = [testapn1, testapn2]
    # 需要检查的目标网卡
    target_network_cards = ["rmnet_data0", "rmnet_data1"]
    
    
    # 检查串口连接状态，确保 debug_serial 已连接
    check_port_status() 
    createLogFile()  # 确保日志文件被创建
    # 打印日志路径，确认日志文件已创建
    print(f"DEBUG_LOG: {DEBUG_LOG}, ADB_LOG: {ADB_LOG}, AT_LOG: {AT_LOG}")
    # 检查串口连接状态，确保 debug_serial 已连接
    check_port_status() 
    # 登录设备
    loginDevice()
    intoTestInterface_testsdk(debug_serial, DEBUG_LOG)
    
    # 循环测试
    while True:
        writeRuntimesToLog()
        
        apn_response = check_APN()
        apn_ids = extract_apn_ids(apn_response)
        check_apn_in_list(apn_ids, target_ids)
        
        set_apn_testsdk(testapn1,testapn1_name)
        set_datacall1_testsdk(datacall1_id,datacall1_name,testapn1)
        start_datacall_testsdk(datacall1_id)
        
        set_apn_testsdk(testapn2,testapn2_name)
        set_datacall1_testsdk(datacall2_id,datacall2_name,testapn2)
        start_datacall_testsdk(datacall2_id)
        
        # network_info = check_network_info()
        # extract_network_info(network_info, target_network_cards)
        
        ping_testsdk()
        
        apn_response = check_APN()
        apn_ids = extract_apn_ids(apn_response)
        check_apn_in_list(apn_ids, target_ids)
        
        remove_datacall_testsdk(datacall1_id)
        remove_datacall_testsdk(datacall2_id)
        
        remove_APN(testapn1)
        remove_APN(testapn2)
        
        apn_response = check_APN()
        apn_ids = extract_apn_ids(apn_response)
        check_apn_in_list(apn_ids, target_ids)
    
# 主程序
if __name__ == '__main__':
    main()